Load libraries
This project uses renv
to keep track of installed packages. Install renv if not
installed and load dependencies with renv::restore().
install.packages("renv")
renv::restore()
library(readr)
library(dplyr)
library(tidyr)
library(reshape2)
library(GenomicRanges)
library(pheatmap)
library(tibble)
library(ggplot2)
library(stringr)
library(cowplot)
library(markdown)
library(RColorBrewer)
library(GenomicAlignments)
library(reshape2)
Read data
- Get list of samples
samples <- read_tsv("config/samples.tsv", show_col_types = FALSE)
units <- read_tsv("config/units.tsv", show_col_types = FALSE)
sample_units <- dplyr::left_join(samples, units, by = "sample_name") %>%
unite(sample_unit, sample_name, unit_name, remove = FALSE)
sample_units
- Read Samtools
idxstats to get human coverage for
normalization
Notes:
- The counts include the total number of reads aligned, they are not
limited to uniquely aligned reads.
- The counts are reads, not pairs or fragments
idxstats_exogenousrna_dir <-
"results/samtools_idxstats/exogenous_rna/"
idxstats_human_dir <-
"results/samtools_idxstats/Homo_sapiens.GRCh38.dna.primary_assembly/"
bowtie2_human_logs <-
"results/logs/bowtie2/Homo_sapiens.GRCh38.dna.primary_assembly/"
idxstats <- tibble()
for (row in seq_len(nrow(sample_units))) {
sample <- sample_units[row, ]$sample_unit
# Read `idsxstats` for exogenous mapped reads
exogenous_rna_stats <- read_tsv(
file.path(idxstats_exogenousrna_dir, sprintf("%s.bam.idxstats", sample)),
col_names = c(
"sequence_name", "sequence_length",
"mapped_reads", "unmapped_reads"
),
col_types = "ciii"
)
exogenous_rna_mapped_reads <- exogenous_rna_stats %>%
filter(!sequence_name %in% c("*")) %>%
select(sequence_name, mapped_reads) %>%
mutate(sample = sample)
# Read `idxstats` for human mapped reads
human_stats <- read_tsv(
file.path(idxstats_human_dir, sprintf("%s.bam.idxstats", sample)),
col_names = c(
"sequence_name", "sequence_length",
"mapped_reads", "unmapped_reads"
),
col_types = "ciii"
)
grch38_mapped_reads <- human_stats %>%
filter(!sequence_name %in% c("*")) %>%
select(mapped_reads) %>%
sum()
grch38_mapped_reads <- tibble(
sequence_name = "grch38_mapped_reads",
mapped_reads = grch38_mapped_reads,
sample = sample
)
# Read bowtie2 logs for unmapped reads
bowtie2_log <- readLines(
file.path(bowtie2_human_logs, sprintf("%s.log", sample))
)
total_pairs <- strtoi(str_split(bowtie2_log[1], " ")[[1]][1])
total_reads <- total_pairs * 2
unmapped_reads <- tibble(
sequence_name = "unmapped",
mapped_reads = total_reads - grch38_mapped_reads$mapped_reads,
sample = sample
)
# Consolidate counts for rows
idxstats <- rbind(
idxstats,
exogenous_rna_mapped_reads,
grch38_mapped_reads,
unmapped_reads
)
}
idxstats
- Read
bedpe files to get exogenous rna coverage of
paired reads
bedpe_data <- tibble()
for (sample in sample_units$sample_unit) {
data <-
readr::read_tsv(
sprintf(
"results/alignments/exogenous_rna/bedpe/%s.bedpe", sample
),
col_names = c(
"chrom1", "chrom1Start", "chrom1End",
"chrom2", "chrom2Start", "chrom2End",
"name", "score", "strand1", "strand2"
),
col_types = "ciiciicicc"
)
bedpe_data <- tibble(rbind(
bedpe_data,
cbind(
sample = sample,
data
)
))
}
bedpe_data
Coverage
Concordant vs Discordant paired reads
Concordant pairs are pairs of reads that:
- Align on the same pegRNA
- Align within 500 bp of each other
- Align in the expected forward-reverse orientation
(
--> .. <--)
Discordant reads aligned but whose mate:
- Did not align (on the pegRNA)
- Aligned more than 500 bp away
- Aligned in an unexpected orientation
## Config and function definition
bam_dir <- "results/alignments/exogenous_rna/sorted"
last_day <- 0
cols <- brewer.pal(n = 5, name = "RdBu")
concordant_cell_line_colors <- list(
"Parental" = "#CA0020",
"P1E10" = "#0571B0"
)
discordant_cell_line_colors <- list(
"Parental" = "#F4A582",
"P1E10" = "#92C5DE"
)
# Exogenous RNA mixtures
rna_mixes <- tibble()
for (mix in c("mastermix1", "mastermix2")) {
t <- readDNAStringSet(sprintf("data/references/%s.fa", mix))
rna_mixes <- rbind(rna_mixes, tibble(
exogenous_rna = mix,
rna_species = word(t@ranges@NAMES, 1),
length = t@ranges@width
))
}
source("pegrna_plots.R")
VEGFA
rna_mix_rows <- rna_mixes %>% filter(grepl("VEGFA", rna_species))
for (norm_factor in c("exogenous_rna_mapped_reads", "grch38_mapped_reads")) {
for (row in seq_len(nrow(rna_mix_rows))) {
rna_species <- rna_mix_rows[[row, "rna_species"]]
mix <- rna_mix_rows[[row, "exogenous_rna"]]
pegrna_plots(
sequence_name = rna_species,
normalization_factor = norm_factor,
mix = mix,
ylab = sprintf("%s coverage (normalized to %s)", mix, norm_factor),
)
}
}




FANCF
for (norm_factor in c("exogenous_rna_mapped_reads", "grch38_mapped_reads")) {
for (rna_species in rna_mixes %>%
filter(grepl("FANCF", rna_species)) %>%
pull(rna_species)) {
pegrna_plots(
sequence_name = rna_species,
normalization_factor = norm_factor,
ylab = sprintf("Coverage (normalized to %s)", norm_factor),
)
}
}


HEK3
for (norm_factor in c("exogenous_rna_mapped_reads", "grch38_mapped_reads")) {
for (rna_species in rna_mixes %>%
filter(grepl("HEK3", rna_species)) %>%
pull(rna_species)) {
pegrna_plots(
sequence_name = rna_species,
normalization_factor = norm_factor,
ylab = sprintf("Coverage (normalized to %s)", norm_factor),
)
}
}




DNMT1
for (norm_factor in c("exogenous_rna_mapped_reads", "grch38_mapped_reads")) {
for (rna_species in rna_mixes %>%
filter(grepl("DNMT1", rna_species)) %>%
pull(rna_species)) {
pegrna_plots(
sequence_name = rna_species,
normalization_factor = norm_factor,
ylab = sprintf("Coverage (normalized to %s)", norm_factor),
)
}
}




RUNX1
for (norm_factor in c("exogenous_rna_mapped_reads", "grch38_mapped_reads")) {
for (rna_species in rna_mixes %>%
filter(grepl("RUNX1", rna_species)) %>%
pull(rna_species)) {
pegrna_plots(
sequence_name = rna_species,
normalization_factor = norm_factor,
ylab = sprintf("Coverage (normalized to %s)", norm_factor),
)
}
}




EMX1
for (norm_factor in c("exogenous_rna_mapped_reads", "grch38_mapped_reads")) {
for (rna_species in rna_mixes %>%
filter(grepl("EMX1", rna_species)) %>%
pull(rna_species)) {
pegrna_plots(
sequence_name = rna_species,
normalization_factor = norm_factor,
ylab = sprintf("Coverage (normalized to %s)", norm_factor),
)
}
}




RNF2
for (norm_factor in c("exogenous_rna_mapped_reads", "grch38_mapped_reads")) {
for (rna_species in rna_mixes %>%
filter(grepl("RNF2", rna_species)) %>%
pull(rna_species)) {
pegrna_plots(
sequence_name = rna_species,
normalization_factor = norm_factor,
ylab = sprintf("Coverage (normalized to %s)", norm_factor),
)
}
}


LS0tCnRpdGxlOiAiQWRhbXNvbiBzbWFsbFJOQSAtIHBlZ1JOQSIKb3V0cHV0OgogIGh0bWxfbm90ZWJvb2s6CiAgICB0b2M6IHRydWUKICAgIGNvZGVfZm9sZGluZzogaGlkZQotLS0KCiMjIExvYWQgbGlicmFyaWVzCgpUaGlzIHByb2plY3QgdXNlcyBbYHJlbnZgXShodHRwczovL3JzdHVkaW8uZ2l0aHViLmlvL3JlbnYvYXJ0aWNsZXMvcmVudi5odG1sKQp0byBrZWVwIHRyYWNrIG9mIGluc3RhbGxlZCBwYWNrYWdlcy4gSW5zdGFsbCBgcmVudmAgaWYgbm90IGluc3RhbGxlZCBhbmQgbG9hZApkZXBlbmRlbmNpZXMgd2l0aCBgcmVudjo6cmVzdG9yZSgpYC4KCmBgYHIKaW5zdGFsbC5wYWNrYWdlcygicmVudiIpCnJlbnY6OnJlc3RvcmUoKQpgYGAKCmBgYHtyIG1lc3NhZ2U9RkFMU0V9CmxpYnJhcnkocmVhZHIpCmxpYnJhcnkoZHBseXIpCmxpYnJhcnkodGlkeXIpCmxpYnJhcnkocmVzaGFwZTIpCmxpYnJhcnkoR2Vub21pY1JhbmdlcykKbGlicmFyeShwaGVhdG1hcCkKbGlicmFyeSh0aWJibGUpCmxpYnJhcnkoZ2dwbG90MikKbGlicmFyeShzdHJpbmdyKQpsaWJyYXJ5KGNvd3Bsb3QpCmxpYnJhcnkobWFya2Rvd24pCmxpYnJhcnkoUkNvbG9yQnJld2VyKQpsaWJyYXJ5KEdlbm9taWNBbGlnbm1lbnRzKQpsaWJyYXJ5KHJlc2hhcGUyKQpgYGAKCiMjIFJlYWQgZGF0YQoKMS4gR2V0IGxpc3Qgb2Ygc2FtcGxlcwoKYGBge3J9CnNhbXBsZXMgPC0gcmVhZF90c3YoImNvbmZpZy9zYW1wbGVzLnRzdiIsIHNob3dfY29sX3R5cGVzID0gRkFMU0UpCnVuaXRzIDwtIHJlYWRfdHN2KCJjb25maWcvdW5pdHMudHN2Iiwgc2hvd19jb2xfdHlwZXMgPSBGQUxTRSkKc2FtcGxlX3VuaXRzIDwtIGRwbHlyOjpsZWZ0X2pvaW4oc2FtcGxlcywgdW5pdHMsIGJ5ID0gInNhbXBsZV9uYW1lIikgJT4lCiAgdW5pdGUoc2FtcGxlX3VuaXQsIHNhbXBsZV9uYW1lLCB1bml0X25hbWUsIHJlbW92ZSA9IEZBTFNFKQpzYW1wbGVfdW5pdHMKYGBgCgoyLiBSZWFkIFNhbXRvb2xzIGBpZHhzdGF0c2AgdG8gZ2V0IGh1bWFuIGNvdmVyYWdlIGZvciBub3JtYWxpemF0aW9uCgpOb3RlczoKCiogVGhlIGNvdW50cyBpbmNsdWRlIHRoZSB0b3RhbCBudW1iZXIgb2YgcmVhZHMgYWxpZ25lZCwgdGhleSAKICBhcmUgbm90IGxpbWl0ZWQgdG8gdW5pcXVlbHkgYWxpZ25lZCByZWFkcy4KKiBUaGUgY291bnRzIGFyZSByZWFkcywgbm90IHBhaXJzIG9yIGZyYWdtZW50cwoKYGBge3J9CmlkeHN0YXRzX2V4b2dlbm91c3JuYV9kaXIgPC0KICAicmVzdWx0cy9zYW10b29sc19pZHhzdGF0cy9leG9nZW5vdXNfcm5hLyIKCmlkeHN0YXRzX2h1bWFuX2RpciA8LQogICJyZXN1bHRzL3NhbXRvb2xzX2lkeHN0YXRzL0hvbW9fc2FwaWVucy5HUkNoMzguZG5hLnByaW1hcnlfYXNzZW1ibHkvIgoKYm93dGllMl9odW1hbl9sb2dzIDwtCiAgInJlc3VsdHMvbG9ncy9ib3d0aWUyL0hvbW9fc2FwaWVucy5HUkNoMzguZG5hLnByaW1hcnlfYXNzZW1ibHkvIgoKaWR4c3RhdHMgPC0gdGliYmxlKCkKCmZvciAocm93IGluIHNlcV9sZW4obnJvdyhzYW1wbGVfdW5pdHMpKSkgewogIHNhbXBsZSA8LSBzYW1wbGVfdW5pdHNbcm93LCBdJHNhbXBsZV91bml0CgogICMgUmVhZCBgaWRzeHN0YXRzYCBmb3IgZXhvZ2Vub3VzIG1hcHBlZCByZWFkcwogIGV4b2dlbm91c19ybmFfc3RhdHMgPC0gcmVhZF90c3YoCiAgICBmaWxlLnBhdGgoaWR4c3RhdHNfZXhvZ2Vub3Vzcm5hX2Rpciwgc3ByaW50ZigiJXMuYmFtLmlkeHN0YXRzIiwgc2FtcGxlKSksCiAgICBjb2xfbmFtZXMgPSBjKAogICAgICAic2VxdWVuY2VfbmFtZSIsICJzZXF1ZW5jZV9sZW5ndGgiLAogICAgICAibWFwcGVkX3JlYWRzIiwgInVubWFwcGVkX3JlYWRzIgogICAgKSwKICAgIGNvbF90eXBlcyA9ICJjaWlpIgogICkKICBleG9nZW5vdXNfcm5hX21hcHBlZF9yZWFkcyA8LSBleG9nZW5vdXNfcm5hX3N0YXRzICU+JQogICAgZmlsdGVyKCFzZXF1ZW5jZV9uYW1lICVpbiUgYygiKiIpKSAlPiUKICAgIHNlbGVjdChzZXF1ZW5jZV9uYW1lLCBtYXBwZWRfcmVhZHMpICU+JQogICAgbXV0YXRlKHNhbXBsZSA9IHNhbXBsZSkKCiAgIyBSZWFkIGBpZHhzdGF0c2AgZm9yIGh1bWFuIG1hcHBlZCByZWFkcwogIGh1bWFuX3N0YXRzIDwtIHJlYWRfdHN2KAogICAgZmlsZS5wYXRoKGlkeHN0YXRzX2h1bWFuX2Rpciwgc3ByaW50ZigiJXMuYmFtLmlkeHN0YXRzIiwgc2FtcGxlKSksCiAgICBjb2xfbmFtZXMgPSBjKAogICAgICAic2VxdWVuY2VfbmFtZSIsICJzZXF1ZW5jZV9sZW5ndGgiLAogICAgICAibWFwcGVkX3JlYWRzIiwgInVubWFwcGVkX3JlYWRzIgogICAgKSwKICAgIGNvbF90eXBlcyA9ICJjaWlpIgogICkKICBncmNoMzhfbWFwcGVkX3JlYWRzIDwtIGh1bWFuX3N0YXRzICU+JQogICAgZmlsdGVyKCFzZXF1ZW5jZV9uYW1lICVpbiUgYygiKiIpKSAlPiUKICAgIHNlbGVjdChtYXBwZWRfcmVhZHMpICU+JQogICAgc3VtKCkKICBncmNoMzhfbWFwcGVkX3JlYWRzIDwtIHRpYmJsZSgKICAgIHNlcXVlbmNlX25hbWUgPSAiZ3JjaDM4X21hcHBlZF9yZWFkcyIsCiAgICBtYXBwZWRfcmVhZHMgPSBncmNoMzhfbWFwcGVkX3JlYWRzLAogICAgc2FtcGxlID0gc2FtcGxlCiAgKQoKICAjIFJlYWQgYm93dGllMiBsb2dzIGZvciB1bm1hcHBlZCByZWFkcwogIGJvd3RpZTJfbG9nIDwtIHJlYWRMaW5lcygKICAgIGZpbGUucGF0aChib3d0aWUyX2h1bWFuX2xvZ3MsIHNwcmludGYoIiVzLmxvZyIsIHNhbXBsZSkpCiAgKQogIHRvdGFsX3BhaXJzIDwtIHN0cnRvaShzdHJfc3BsaXQoYm93dGllMl9sb2dbMV0sICIgIilbWzFdXVsxXSkKICB0b3RhbF9yZWFkcyA8LSB0b3RhbF9wYWlycyAqIDIKICB1bm1hcHBlZF9yZWFkcyA8LSB0aWJibGUoCiAgICBzZXF1ZW5jZV9uYW1lID0gInVubWFwcGVkIiwKICAgIG1hcHBlZF9yZWFkcyA9IHRvdGFsX3JlYWRzIC0gZ3JjaDM4X21hcHBlZF9yZWFkcyRtYXBwZWRfcmVhZHMsCiAgICBzYW1wbGUgPSBzYW1wbGUKICApCgogICMgQ29uc29saWRhdGUgY291bnRzIGZvciByb3dzCiAgaWR4c3RhdHMgPC0gcmJpbmQoCiAgICBpZHhzdGF0cywKICAgIGV4b2dlbm91c19ybmFfbWFwcGVkX3JlYWRzLAogICAgZ3JjaDM4X21hcHBlZF9yZWFkcywKICAgIHVubWFwcGVkX3JlYWRzCiAgKQp9CmlkeHN0YXRzCmBgYAoKMy4gUmVhZCBgYmVkcGVgIGZpbGVzIHRvIGdldCBleG9nZW5vdXMgcm5hIGNvdmVyYWdlIG9mIHBhaXJlZCByZWFkcwoKYGBge3J9CmJlZHBlX2RhdGEgPC0gdGliYmxlKCkKZm9yIChzYW1wbGUgaW4gc2FtcGxlX3VuaXRzJHNhbXBsZV91bml0KSB7CiAgZGF0YSA8LQogICAgcmVhZHI6OnJlYWRfdHN2KAogICAgICBzcHJpbnRmKAogICAgICAgICJyZXN1bHRzL2FsaWdubWVudHMvZXhvZ2Vub3VzX3JuYS9iZWRwZS8lcy5iZWRwZSIsIHNhbXBsZQogICAgICApLAogICAgICBjb2xfbmFtZXMgPSBjKAogICAgICAgICJjaHJvbTEiLCAiY2hyb20xU3RhcnQiLCAiY2hyb20xRW5kIiwKICAgICAgICAiY2hyb20yIiwgImNocm9tMlN0YXJ0IiwgImNocm9tMkVuZCIsCiAgICAgICAgIm5hbWUiLCAic2NvcmUiLCAic3RyYW5kMSIsICJzdHJhbmQyIgogICAgICApLAogICAgICBjb2xfdHlwZXMgPSAiY2lpY2lpY2ljYyIKICAgICkKICBiZWRwZV9kYXRhIDwtIHRpYmJsZShyYmluZCgKICAgIGJlZHBlX2RhdGEsCiAgICBjYmluZCgKICAgICAgc2FtcGxlID0gc2FtcGxlLAogICAgICBkYXRhCiAgICApCiAgKSkKfQpiZWRwZV9kYXRhCmBgYAoKIyMgQ292ZXJhZ2UKCiMjIyBDb25jb3JkYW50IHZzIERpc2NvcmRhbnQgcGFpcmVkIHJlYWRzCgpDb25jb3JkYW50IHBhaXJzIGFyZSBwYWlycyBvZiByZWFkcyB0aGF0OgoKKiBBbGlnbiBvbiB0aGUgc2FtZSBwZWdSTkEKKiBBbGlnbiB3aXRoaW4gNTAwIGJwIG9mIGVhY2ggb3RoZXIKKiBBbGlnbiBpbiB0aGUgZXhwZWN0ZWQgZm9yd2FyZC1yZXZlcnNlIG9yaWVudGF0aW9uIChgLS0+IC4uIDwtLWApCgpEaXNjb3JkYW50IHJlYWRzIGFsaWduZWQgYnV0IHdob3NlIG1hdGU6CgoqIERpZCBub3QgYWxpZ24gKG9uIHRoZSBwZWdSTkEpCiogQWxpZ25lZCBtb3JlIHRoYW4gNTAwIGJwIGF3YXkKKiBBbGlnbmVkIGluIGFuIHVuZXhwZWN0ZWQgb3JpZW50YXRpb24KCmBgYHtyIGZpZy53aWR0aD0xMCwgZmlnLmhlaWdodD0xMH0KIyMgQ29uZmlnIGFuZCBmdW5jdGlvbiBkZWZpbml0aW9uCgpiYW1fZGlyIDwtICJyZXN1bHRzL2FsaWdubWVudHMvZXhvZ2Vub3VzX3JuYS9zb3J0ZWQiCgpsYXN0X2RheSA8LSAwCmNvbHMgPC0gYnJld2VyLnBhbChuID0gNSwgbmFtZSA9ICJSZEJ1IikKCmNvbmNvcmRhbnRfY2VsbF9saW5lX2NvbG9ycyA8LSBsaXN0KAogICJQYXJlbnRhbCIgPSAiI0NBMDAyMCIsCiAgIlAxRTEwIiA9ICIjMDU3MUIwIgopCgpkaXNjb3JkYW50X2NlbGxfbGluZV9jb2xvcnMgPC0gbGlzdCgKICAiUGFyZW50YWwiID0gIiNGNEE1ODIiLAogICJQMUUxMCIgPSAiIzkyQzVERSIKKQoKIyBFeG9nZW5vdXMgUk5BIG1peHR1cmVzCnJuYV9taXhlcyA8LSB0aWJibGUoKQpmb3IgKG1peCBpbiBjKCJtYXN0ZXJtaXgxIiwgIm1hc3Rlcm1peDIiKSkgewogIHQgPC0gcmVhZEROQVN0cmluZ1NldChzcHJpbnRmKCJkYXRhL3JlZmVyZW5jZXMvJXMuZmEiLCBtaXgpKQogIHJuYV9taXhlcyA8LSByYmluZChybmFfbWl4ZXMsIHRpYmJsZSgKICAgIGV4b2dlbm91c19ybmEgPSBtaXgsCiAgICBybmFfc3BlY2llcyA9IHdvcmQodEByYW5nZXNATkFNRVMsIDEpLAogICAgbGVuZ3RoID0gdEByYW5nZXNAd2lkdGgKICApKQp9Cgpzb3VyY2UoInBlZ3JuYV9wbG90cy5SIikKYGBgCgojIyMgVkVHRkEKCmBgYHtyIGZpZy53aWR0aD0xMCwgZmlnLmhlaWdodD0xMH0Kcm5hX21peF9yb3dzIDwtIHJuYV9taXhlcyAlPiUgZmlsdGVyKGdyZXBsKCJWRUdGQSIsIHJuYV9zcGVjaWVzKSkKCmZvciAobm9ybV9mYWN0b3IgaW4gYygiZXhvZ2Vub3VzX3JuYV9tYXBwZWRfcmVhZHMiLCAiZ3JjaDM4X21hcHBlZF9yZWFkcyIpKSB7CiAgZm9yIChyb3cgaW4gc2VxX2xlbihucm93KHJuYV9taXhfcm93cykpKSB7CiAgICBybmFfc3BlY2llcyA8LSBybmFfbWl4X3Jvd3NbW3JvdywgInJuYV9zcGVjaWVzIl1dCiAgICBtaXggPC0gcm5hX21peF9yb3dzW1tyb3csICJleG9nZW5vdXNfcm5hIl1dCgogICAgcGVncm5hX3Bsb3RzKAogICAgICBzZXF1ZW5jZV9uYW1lID0gcm5hX3NwZWNpZXMsCiAgICAgIG5vcm1hbGl6YXRpb25fZmFjdG9yID0gbm9ybV9mYWN0b3IsCiAgICAgIG1peCA9IG1peCwKICAgICAgeWxhYiA9IHNwcmludGYoIiVzIGNvdmVyYWdlIChub3JtYWxpemVkIHRvICVzKSIsIG1peCwgbm9ybV9mYWN0b3IpLAogICAgKQogIH0KfQpgYGAKCiMjIyBGQU5DRgoKYGBge3IgZmlnLndpZHRoPTEwLCBmaWcuaGVpZ2h0PTEwfQpmb3IgKG5vcm1fZmFjdG9yIGluIGMoImV4b2dlbm91c19ybmFfbWFwcGVkX3JlYWRzIiwgImdyY2gzOF9tYXBwZWRfcmVhZHMiKSkgewogIGZvciAocm5hX3NwZWNpZXMgaW4gcm5hX21peGVzICU+JQogICAgZmlsdGVyKGdyZXBsKCJGQU5DRiIsIHJuYV9zcGVjaWVzKSkgJT4lCiAgICBwdWxsKHJuYV9zcGVjaWVzKSkgewogICAgcGVncm5hX3Bsb3RzKAogICAgICBzZXF1ZW5jZV9uYW1lID0gcm5hX3NwZWNpZXMsCiAgICAgIG5vcm1hbGl6YXRpb25fZmFjdG9yID0gbm9ybV9mYWN0b3IsCiAgICAgIHlsYWIgPSBzcHJpbnRmKCJDb3ZlcmFnZSAobm9ybWFsaXplZCB0byAlcykiLCBub3JtX2ZhY3RvciksCiAgICApCiAgfQp9CmBgYAoKIyMjIEhFSzMKCmBgYHtyIGZpZy53aWR0aD0xMCwgZmlnLmhlaWdodD0xMH0KZm9yIChub3JtX2ZhY3RvciBpbiBjKCJleG9nZW5vdXNfcm5hX21hcHBlZF9yZWFkcyIsICJncmNoMzhfbWFwcGVkX3JlYWRzIikpIHsKICBmb3IgKHJuYV9zcGVjaWVzIGluIHJuYV9taXhlcyAlPiUKICAgIGZpbHRlcihncmVwbCgiSEVLMyIsIHJuYV9zcGVjaWVzKSkgJT4lCiAgICBwdWxsKHJuYV9zcGVjaWVzKSkgewogICAgcGVncm5hX3Bsb3RzKAogICAgICBzZXF1ZW5jZV9uYW1lID0gcm5hX3NwZWNpZXMsCiAgICAgIG5vcm1hbGl6YXRpb25fZmFjdG9yID0gbm9ybV9mYWN0b3IsCiAgICAgIHlsYWIgPSBzcHJpbnRmKCJDb3ZlcmFnZSAobm9ybWFsaXplZCB0byAlcykiLCBub3JtX2ZhY3RvciksCiAgICApCiAgfQp9CmBgYAoKCgojIyMjIEROTVQxCgpgYGB7ciBmaWcud2lkdGg9MTAsIGZpZy5oZWlnaHQ9MTB9CmZvciAobm9ybV9mYWN0b3IgaW4gYygiZXhvZ2Vub3VzX3JuYV9tYXBwZWRfcmVhZHMiLCAiZ3JjaDM4X21hcHBlZF9yZWFkcyIpKSB7CiAgZm9yIChybmFfc3BlY2llcyBpbiBybmFfbWl4ZXMgJT4lCiAgICBmaWx0ZXIoZ3JlcGwoIkROTVQxIiwgcm5hX3NwZWNpZXMpKSAlPiUKICAgIHB1bGwocm5hX3NwZWNpZXMpKSB7CiAgICBwZWdybmFfcGxvdHMoCiAgICAgIHNlcXVlbmNlX25hbWUgPSBybmFfc3BlY2llcywKICAgICAgbm9ybWFsaXphdGlvbl9mYWN0b3IgPSBub3JtX2ZhY3RvciwKICAgICAgeWxhYiA9IHNwcmludGYoIkNvdmVyYWdlIChub3JtYWxpemVkIHRvICVzKSIsIG5vcm1fZmFjdG9yKSwKICAgICkKICB9Cn0KYGBgCgoKIyMjIFJVTlgxCgpgYGB7ciBmaWcud2lkdGg9MTAsIGZpZy5oZWlnaHQ9MTB9CmZvciAobm9ybV9mYWN0b3IgaW4gYygiZXhvZ2Vub3VzX3JuYV9tYXBwZWRfcmVhZHMiLCAiZ3JjaDM4X21hcHBlZF9yZWFkcyIpKSB7CiAgZm9yIChybmFfc3BlY2llcyBpbiBybmFfbWl4ZXMgJT4lCiAgICBmaWx0ZXIoZ3JlcGwoIlJVTlgxIiwgcm5hX3NwZWNpZXMpKSAlPiUKICAgIHB1bGwocm5hX3NwZWNpZXMpKSB7CiAgICBwZWdybmFfcGxvdHMoCiAgICAgIHNlcXVlbmNlX25hbWUgPSBybmFfc3BlY2llcywKICAgICAgbm9ybWFsaXphdGlvbl9mYWN0b3IgPSBub3JtX2ZhY3RvciwKICAgICAgeWxhYiA9IHNwcmludGYoIkNvdmVyYWdlIChub3JtYWxpemVkIHRvICVzKSIsIG5vcm1fZmFjdG9yKSwKICAgICkKICB9Cn0KYGBgCgojIyMgRU1YMQoKYGBge3IgZmlnLndpZHRoPTEwLCBmaWcuaGVpZ2h0PTEwfQpmb3IgKG5vcm1fZmFjdG9yIGluIGMoImV4b2dlbm91c19ybmFfbWFwcGVkX3JlYWRzIiwgImdyY2gzOF9tYXBwZWRfcmVhZHMiKSkgewogIGZvciAocm5hX3NwZWNpZXMgaW4gcm5hX21peGVzICU+JQogICAgZmlsdGVyKGdyZXBsKCJFTVgxIiwgcm5hX3NwZWNpZXMpKSAlPiUKICAgIHB1bGwocm5hX3NwZWNpZXMpKSB7CiAgICBwZWdybmFfcGxvdHMoCiAgICAgIHNlcXVlbmNlX25hbWUgPSBybmFfc3BlY2llcywKICAgICAgbm9ybWFsaXphdGlvbl9mYWN0b3IgPSBub3JtX2ZhY3RvciwKICAgICAgeWxhYiA9IHNwcmludGYoIkNvdmVyYWdlIChub3JtYWxpemVkIHRvICVzKSIsIG5vcm1fZmFjdG9yKSwKICAgICkKICB9Cn0KYGBgCgojIyMgUk5GMgoKYGBge3IgZmlnLndpZHRoPTEwLCBmaWcuaGVpZ2h0PTEwfQpmb3IgKG5vcm1fZmFjdG9yIGluIGMoImV4b2dlbm91c19ybmFfbWFwcGVkX3JlYWRzIiwgImdyY2gzOF9tYXBwZWRfcmVhZHMiKSkgewogIGZvciAocm5hX3NwZWNpZXMgaW4gcm5hX21peGVzICU+JQogICAgZmlsdGVyKGdyZXBsKCJSTkYyIiwgcm5hX3NwZWNpZXMpKSAlPiUKICAgIHB1bGwocm5hX3NwZWNpZXMpKSB7CiAgICBwZWdybmFfcGxvdHMoCiAgICAgIHNlcXVlbmNlX25hbWUgPSBybmFfc3BlY2llcywKICAgICAgbm9ybWFsaXphdGlvbl9mYWN0b3IgPSBub3JtX2ZhY3RvciwKICAgICAgeWxhYiA9IHNwcmludGYoIkNvdmVyYWdlIChub3JtYWxpemVkIHRvICVzKSIsIG5vcm1fZmFjdG9yKSwKICAgICkKICB9Cn0KYGBgCg==